<?php
/**
 * Created by PhpStorm.
 *
 * @Date: 2018-01-08
 * @Time: 18:10
 * @Author: cdkay
 * @Email: network@iyuanma.net
 *
 * @File： Allinpay.php
 */
namespace app\site\controller;

use app\common\model\BuyBill;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;
use think\Controller;
use think\Db;
use think\Log;
use think\Request;
use think\Validate;

class Allinpay extends Controller {
    /**
     * getCourse
     * 获取课程数据
     *
     * @author zhengkai
     * @date 2018-01-09
     *
     * @param int $id 课程id
     * @return mixed
     */
    protected static function getCourse($id)
    {
        // 查询获取课程数据
        $data = Db::query("select * from curriculum where curriculum_id={$id}");

        if (empty($data)) {
            Log::error('通联支付错误信息：购买的课程不存在');
            echo '<script>alert("商品不存在");window.close();</script>';
            return false;
        }

        $data = $data[0];

        // 促销价格
        $data['curriculum_sales_price'] = $data['curriculum_sale_price'];

        // 判断是否参加了优惠促销
        $now = time();
        if ($data['curriculum_sales']>0) {
            $sales = Db::query("select * from sales where (sales_id={$data['curriculum_sales']}) and ((sales_start_time<{$now}) and (sales_end_time>{$now}))");
            if ($sales) {
                $sales = $sales[0];

                switch ($sales['sales_type']) {
                    case 1: // 折扣
                        // 当有促销活动时临时调整价格：销售价格为优惠后的价格
                        $data['curriculum_sales_price'] = (((int)$sales['sales_discount']/100)*$data['curriculum_sale_price']);
                        // 赠品
                        $data['curriculum_gift'] = $sales['gifts'];
                        break;
                    case 2: // 减免金额
                        // 当有促销活动时临时调整价格：销售价格为优惠后的价格
                        $data['curriculum_sales_price'] = ($data['curriculum_sale_price']-$sales['sales_amount']);
                        // 赠品
                        $data['curriculum_gift'] = $sales['gifts'];
                        break;
                    default :
                        // 赠品
                        $data['curriculum_gift'] = $sales['gifts'];
                }
            } else {
                $data['curriculum_sales_price'] = $data['curriculum_sale_price'];
            }
        } else {
            $data['curriculum_sales_price'] = $data['curriculum_sale_price'];
        }

        return $data;
    }

    // todo 获取直播数据
    protected static function getLive($id)
    {

    }

    /**
     * getSpecial
     * 获取专栏数据
     *
     * @author zhengkai
     * @date 2018-05-03
     *
     * @param $id
     * @return bool|mixed
     */
    protected static function getSpecial($id)
    {
        $data = Db::query("select * from special_column where column_id=:id", ['id'=>$id]);
        if (empty($data)) {
            Log::error('通联支付错误信息：订阅的专栏不存在');
            echo '<script>alert("商品不存在");window.close();</script>';
            return false;
        }

        $data = $data[0];

        // 促销价格
        $data['column_sale_price'] = $data['column_price'];

        // 判断是否参加了优惠促销
        $now = time();
        if ($data['column_sales']>0) {
            $sales = Db::query("select * from sales where (sales_id={$data['column_sales']}) and ((sales_start_time<{$now}) and (sales_end_time>{$now}))");
            if ($sales) {
                $sales = $sales[0];

                switch ($sales['sales_type']) {
                    case 1: // 折扣
                        // 当有促销活动时临时调整价格：销售价格为优惠后的价格
                        $data['column_sales_price'] = (((int)$sales['sales_discount']/100)*$data['column_price']);
                        // 赠品
                        $data['column_gift'] = $sales['gifts'];
                        break;
                    case 2: // 减免金额
                        // 当有促销活动时临时调整价格：销售价格为优惠后的价格
                        $data['column_sales_price'] = ($data['column_price']-$sales['sales_amount']);
                        // 赠品
                        $data['column_gift'] = $sales['gifts'];
                        break;
                    default :
                        // 赠品
                        $data['column_gift'] = $sales['gifts'];
                }
            } else {
                $data['column_sales_price'] = $data['column_price'];
            }
        } else {
            $data['column_sales_price'] = $data['column_price'];
        }

        return $data;
    }


    /**
     * createOrder
     * 创建订单
     *
     * @author zhengkai
     * @date 2018-01-09
     *
     * @param array $param
     * @return bool
     */
    protected function createOrder($param)
    {
        $paramList = [
            'bill_item_type',
            'bill_item_id',
            'bill_payable_amount',
            'bill_pay_amount',
            'bill_user',
            'bill_no',
            'bill_source',
            'bill_pay_method',
            'bill_item_title',
            'bill_item_detail',
            'bill_type',
            'bill_trade_way',
            'gifts'
        ];

        foreach($paramList as $column) {
            if(!isset($param[$column])) {
                Log::error("通联支付错误信息：创建订单，缺少参数{$column}");
                echo '<script>alert("订单创建失败，缺少参数");window.close();</script>';
                return false;
            }
        }

        Db::startTrans();
        try {

            $data = [
                'bill_item_type' => $param['bill_item_type'],
                'bill_item_id' => $param['bill_item_id'],
                'bill_payable_amount' => $param['bill_payable_amount'],
                'bill_pay_amount' => $param['bill_pay_amount'],
                'bill_createtime' => time(),
                'bill_user' => $param['bill_user'],
                'bill_no' => $param['bill_no'],
                'bill_source' => $param['bill_source'],
                'bill_pay_method' => $param['bill_pay_method'],
                'bill_item_title' => $param['bill_item_title'],
                'bill_item_detail' => $param['bill_item_detail'],
                'bill_type' => $param['bill_type'],
                'bill_trade_way' => $param['bill_trade_way'],
                'gifts' => $param['gifts']
            ];
            Db::table('buy_bill')->insert($data);

            Db::commit();
            return true;

        } catch (\Exception $e) {
            Log::error("通联支付错误信息：创建订单，{$e->getMessage()}");
            echo '<script>alert("订单创建失败");window.close();</script>';
            return false;
        }
    }

    /**
     * pay
     * 通联支付请求处理
     *
     * @author zhengkai
     * @date 2018-01-09
     *
     * @return array|string|\think\response\View
     */
    public function pay()
    {
        if (!Request::instance()->isPost()) return '<script>alert("请求错误");window.close();</script>'; // "请求错误";

        // 获取用户ID
        $uid = checkUserLogin(true);

        $form = input('post.');

        // 表单验证
        $validate = new Validate([
            ['uid', 'require|^\\d+$', '用户ID不能为空|uid参数类型不正确'],
            ['token', 'require', 'token不能为空'],
            ['notLoginUrl', 'url', 'notLoginUrl不是一个有效的url参数'],
            ['item_type', 'require|^\\d+$', '商品类型不能为空|item_type参数类型不正确'],
            ['item_id', 'require|^\\d+$', '商品ID不能为空|item_id参数类型不正确'],
            ['pickupUrl', 'require|url', '支付完成回调地址不能为空|pickupUrl不是一个有效的url'],
        ]);
        if(!$validate->check($form)) return $validate->getError();

        // 当用户id返回的不是数字，且“未登录跳转url”参数不为空时则跳转到指定的url
        if (!is_numeric($uid) && !isset($form['notLoginUrl'])) redirect($form['notLoginUrl']);

        // 获取已存在的订单数据
        $buyBill = BuyBill::get([
            'bill_item_type' => $form['item_type'],
            'bill_item_id' => $form['item_id'],
            'bill_user' => $uid,
        ]);

        if ($buyBill && $buyBill->bill_have_paid) return '<script>alert("您已购买过该商品");window.close();</script>';

        $isOrder = false; // 订单是否忆存在
        if ($buyBill && !$buyBill->bill_have_paid) $isOrder = true;


        // 获取商品数据
        switch ($form['item_type']) {
            case 1: // 课程
                $data = self::getCourse($form['item_id']);
                $data = [
                    'goods_id' => $data['curriculum_id'],
                    'goods_name' => '课程：'.$data['curriculum_name'],
                    'goods_sale_price' => $data['curriculum_sales_price'], // 应付
                    'goods_sales_price' => $data['curriculum_sales_price'], // 实付
                    'goods_gift' => $data['curriculum_gift']??'{}', // 赠品
                    'goods_description' => $data['curriculum_summary']??$data['curriculum_name']
                ];
                break;
            case 2: // 直播
                break;
            case 3: // 专栏
                $data = self::getSpecial($form['item_id']);
                $data = [
                    'goods_id' => $data['column_id'],
                    'goods_name' => '专栏：'.$data['column_title'],
                    'goods_sale_price' => $data['column_sale_price'], // 应付
                    'goods_sales_price' => $data['column_sales_price'], // 实付
                    'goods_gift' => $data['column_gift']??'{}', // 赠品
                    'goods_description' => $data['column_description']??$data['column_title']
                ];
                break;
        }

        // 订单号
        $orderNo = $isOrder?$buyBill->bill_no:BuyBill::generateOrderNo($uid);
        // 订单金额
        $orderAmount = intval($data['goods_sale_price']*100);

        // 支付扩展参数
        $ext = $form['pickupUrl']; // 支付结果展示页面地址

        // 支付提交参数
        $payParam = [
            'inputCharset' => 1,                                                                    // 字符集编码 1=utf8
            'pickupUrl' => Request::instance()->domain().url('site/Allinpay/pickup'),              // 支付结果展示页面地址 必填
            'receiveUrl' => Request::instance()->domain().url('callback/Pay/allinpay'),         // 支付结果通知地址 必填
            'version' => 'v1.0',                                                                    // 请求接口版本 必填
            'language' => 1,                                                                        // 网关页面语言 1=简体中文
            'signType' => 0,                                                                        // 签名类型 必填
            'merchantId' => config('allinpay.merchantId'),                                   // 商户号 必填
            'payerName' => '',                                                                      // 付款人姓名
            'payerEmail' => '',                                                                     // 付款人邮箱
            'payerTelephone' => '',                                                                 // 付款人电话
            'payerIDCard' => '',                                                                    // 付款人证件类型及证件号
            'pid' => '',                                                                            // 合作伙伴商户号
            'orderNo' => $orderNo,                                                                  // 商户订单号 必填
            'orderAmount' => $orderAmount,                                                          // 商户订单金额，单位：分 必填
            'orderCurrency' => 0,                                                                   // 货币类型 0、156=人民币
            'orderDatetime' => date('YmdHms', time()),                                       // 订单提交时间，格式yyyyMMDDhhmmss 必填
            'orderExpireDatetime' => 1440,                                                          // 订单过期时间，单位：分钟，最大9999分钟
            'productName' => $data['goods_name'],                                                   // 商品名称
            'productPrice' => $data['goods_sale_price'],                                           // 商品价格
            'productNum' => 1,                                                                      // 商品数量
            'productId' => $data['goods_id'],                                                       // 商品代码（ID）
            'productDesc' => $data['goods_description'],                                            // 商品描述
            'ext1' => $ext,                                                                         // 扩展字段，支付完成后返回
            'ext2' => '',                                                                           // 扩展字段，支付完成后返回
            'extTL' => '',                                                                          // 业务扩展字段
            'payType' => 0,                                                                         // 支付方式 0=商户已开通的所有 必填
            'issuerId' => '',                                                                       // 发卡方代码，payType字段为0时留空
            'pan' => '',                                                                            // 付款人卡号
            'tradeNature' => 'SERVICES',                                                            // 贸易类型
            'signMsg' => '',                                                                        // 签名字符串
            'customsExt' => ''                                                                      // 海关扩展字段
        ];

        $certFile = file_get_contents(ROOT_PATH.config('allinpay.cert'));
        $x509 = new X509();
        $rsa = new RSA();

        //需要加密付款人身份证信息
        if($payParam['payerIDCard'] != "") {;
            $cert = $x509->loadX509($certFile);
            $pubkey = $x509->getPublicKey();
            $rsa->loadKey($pubkey);
            $rsa->setPublicKey();
            $rsa->setEncryptionMode(RSA::SIGNATURE_PKCS1);

            $ciphertext = $rsa->encrypt($payParam['payerIDCard']);
            $ciphertext = base64_encode($ciphertext);


            $payParam['payerIDCard'] = $ciphertext;
        }

        //如果海关扩展字段不为空，需要做个MD5填写到ext2里
        if($payParam['ext2'] == "" && $payParam['customsExt'] != "") $payParam['ext2'] = strtoupper(md5($payParam['customsExt']));

        // 拼接签名字符串
        $singMsg = '';
        foreach ($payParam as $key=>$val) {
            if ($val !== "") $singMsg .= $key.'='.$val.'&';
        }
        $singMsg = $singMsg.'key='.config('allinpay.md5Key');
        $payParam['signMsg'] = strtoupper(md5($singMsg));

        if (!$isOrder) {
            // 创建订单
            $orderData = [
                'bill_item_type' => $form['item_type'],
                'bill_item_id' => $form['item_id'],
                'bill_payable_amount' => $data['goods_sale_price'],
                'bill_pay_amount' => $data['goods_sales_price'],
                'bill_createtime' => time(),
                'bill_user' => $uid,
                'bill_no' => $orderNo,
                'bill_source' => 3,
                'bill_pay_method' => 3, // 交易方式 3=通联支付
                'bill_item_title' => $data['goods_name'],
                'bill_item_detail' => $data['goods_description'],
                'bill_type' => 1,
                'bill_trade_way' => 1,
                'gifts' => $data['goods_gift']
            ];
            $createOrder = $this->createOrder($orderData);
        }


        if ($isOrder || (!$isOrder && $createOrder)) {
            // 生成参数表单
            $formStr = '';
            foreach ($payParam as $key=>$val) {
                $formStr .= "<input type=\"hidden\" name=\"{$key}\" value=\"{$val}\">".PHP_EOL;
            }
            $this->assign('form', $formStr);
            $allinpayDo = config('allinpay.payServer');
            $this->assign('allinpayServer', $allinpayDo);

            return view('allinpay/pay');
        } else {
            // return "支付请求失败";
            return '<script>alert("支付请求失败");window.close();</script>';
        }
    }

    /**
     * pickup
     * 通联支付，支付完成后支付结果展示页面跳转处理
     */
    public function pickup()
    {
        $form = input('post.');

        $pickupUrl = $form['ext1'];

        header('Location: '.$pickupUrl);
    }
}